﻿//"The contents of this file are subject to the Mozilla Public License
//Version 1.1 (the "License"); you may not use this file except in
//compliance with the License. You may obtain a copy of the License at
//http://www.mozilla.org/MPL/

//Software distributed under the License is distributed on an "AS IS"
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//License for the specific language governing rights and limitations
//under the License.

//The Original Code is TSharp.

//The Initial Developer of the Original Code is Mar3ek (http://mar3ek.wordpress.com).
//Portions created by Mar3ek are Copyright (C) 2010
//Mar3ek (http://mar3ek.wordpress.com). All Rights Reserved.

//Contributor(s): ______________________________________.

//Alternatively, the contents of this file may be used under the terms
//of the _____ license (the  "[___] License"), in which case the
//provisions of [______] License are applicable instead of those
//above.  If you wish to allow use of your version of this file only
//under the terms of the [____] License and not to allow others to use
//your version of this file under the MPL, indicate your decision by
//deleting  the provisions above and replace  them with the notice and
//other provisions required by the [___] License.  If you do not delete
//the provisions above, a recipient may use your version of this file
//under either the MPL or the [___] License."

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.Linq;

namespace TSharp
{
    public partial class Twitter
    {
        #region Timeline

        /// <summary>
        /// Returns the <i>count</i> most recent statuses, including retweets if they exist, posted by the authenticating user and the user's they follow.
        /// </summary>
        /// <param name="lastTweet">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        /// <param name="count">Number of tweets to retrieve (must be less than or equal to 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of tweets</returns>
        public Collection<Tweet> GetHomeTimeline(ulong lastTweet, uint count)
        {
            if (lastTweet < 1) throw new ArgumentOutOfRangeException("lastTweet");
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/home_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()),
                                        new KeyValuePair<string, string>("since_id", lastTweet.ToString()));
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the 20 most recent statuses, including retweets if they exist, posted by the authenticating user and the user's they follow.
        /// </summary>
        /// <returns>List of tweets</returns>
        /// <seealso cref="GetHomeTimeline()"/>
        /// <seealso cref="GetHomeTimeline(byte)"/>
        /// <seealso cref="GetHomeTimeline(uint)"/>
        public Collection<Tweet> GetHomeTimeline()
        {
            var result = SendRequest(RequestMethod.Get, "https://api.twitter.com/1/statuses/home_timeline.xml", true);
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the <i>count</i> most recent statuses, including retweets if they exist, posted by the authenticating user and the user's they follow.
        /// </summary>
        /// <param name="count">Specifies the number of records to retrieve (must be less than or equal to 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of tweets</returns>
        /// <seealso cref="GetHomeTimeline()"/>
        /// <seealso cref="GetHomeTimeline(byte)"/>
        public Collection<Tweet> GetHomeTimeline(uint count)
        {
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/home_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the 20 most recent statuses, including retweets if they exist, posted by the authenticating user and the user's they follow.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of tweets</returns>
        /// <seealso cref="GetHomeTimeline()"/>
        /// <seealso cref="GetHomeTimeline(uint)"/>
        public Collection<Tweet> GetHomeTimeline(byte page)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/home_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the <i>count</i> most recent statuses posted by the authenticating user and the user's they follow.
        /// </summary>
        /// <param name="lastTweet">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        /// <param name="count">Number of tweets to retrieve (must be less than or equal to 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of tweets</returns>
        /// <seealso cref="GetFriendsTimeline()"/>
        /// <seealso cref="GetFriendsTimeline(uint)"/>
        /// <seealso cref="GetFriendsTimeline(byte)"/>
        public Collection<Tweet> GetFriendsTimeline(ulong lastTweet, uint count)
        {
            if (lastTweet < 1) throw new ArgumentOutOfRangeException("lastTweet");
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/friends_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()),
                                        new KeyValuePair<string, string>("since_id", lastTweet.ToString()));
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the 20 most recent statuses posted by the authenticating user and the user's they follow.
        /// </summary>
        /// <returns>List of tweets</returns>
        /// <seealso cref="GetFriendsTimeline(ulong, uint)"/>
        /// <seealso cref="GetFriendsTimeline(uint)"/>
        /// <seealso cref="GetFriendsTimeline(byte)"/>
        public Collection<Tweet> GetFriendsTimeline()
        {
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/friends_timeline.xml",
                                        true);
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the <i>count</i> most recent statuses posted by the authenticating user and the user's they follow.
        /// </summary>
        /// <param name="count">Specifies the number of records to retrieve (must be less than or equal to 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of tweets</returns>
        /// <seealso cref="GetFriendsTimeline()"/>
        /// <seealso cref="GetFriendsTimeline(ulong, uint)"/>
        /// <seealso cref="GetFriendsTimeline(byte)"/>
        public Collection<Tweet> GetFriendsTimeline(uint count)
        {
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/friends_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the 20 most recent statuses posted by the authenticating user and the user's they follow.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of tweets</returns>
        /// <seealso cref="GetFriendsTimeline()"/>
        /// <seealso cref="GetFriendsTimeline(ulong, uint)"/>
        /// <seealso cref="GetFriendsTimeline(uint)"/>
        public Collection<Tweet> GetFriendsTimeline(byte page)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/friends_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent statuses posted by the specified user.
        ///</summary>
        ///<param name="screenName">The screen name of the user for whom to return results for</param>
        ///<returns>List of tweets</returns>
        ///<exception cref="ArgumentNullException" />
        public Collection<Tweet> GetUsersTimeline(string screenName)
        {
            if (string.IsNullOrEmpty(screenName)) throw new ArgumentNullException("screenName");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("screen_name", screenName));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent statuses posted by the specified user.
        ///</summary>
        ///<param name="userId">The ID of the user for whom to return results for</param>
        ///<returns>List of tweets</returns>
        /// <remarks>The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.</remarks>
        ///<exception cref="ArgumentOutOfRangeException" />
        public Collection<Tweet> GetUsersTimeline(ulong userId)
        {
            if (userId < 1) throw new ArgumentOutOfRangeException("userId");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("user_id", userId.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent statuses posted by the specified user.
        ///</summary>
        ///<param name="screenName">The screen name of the user for whom to return results for</param>
        ///<param name="page">Specifies the page of results to retrieve</param>
        ///<exception cref="ArgumentOutOfRangeException" />
        ///<exception cref="ArgumentNullException" />
        ///<returns>List of tweets</returns>
        /// <remarks>The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.</remarks>
        public Collection<Tweet> GetUsersTimeline(string screenName, uint page)
        {
            if (string.IsNullOrEmpty(screenName)) throw new ArgumentNullException("screenName");
            if (page < 1) throw new ArgumentOutOfRangeException("page");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("screen_name", screenName),
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent statuses posted by the specified user.
        ///</summary>
        ///<param name="userId">The ID of the user for whom to return results for</param>
        ///<param name="page">Specifies the page of results to retrieve</param>
        ///<returns>List of tweets</returns>
        /// <remarks>The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.</remarks>
        ///<exception cref="ArgumentOutOfRangeException" />
        public Collection<Tweet> GetUsersTimeline(ulong userId, uint page)
        {
            if (userId < 1) throw new ArgumentOutOfRangeException("userId");
            if (page < 1) throw new ArgumentOutOfRangeException("page");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("user_id", userId.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent statuses posted by the specified user.
        ///</summary>
        ///<param name="screenName">The screen name of the user for whom to return results for</param>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<returns>List of tweets</returns>
        ///<exception cref="ArgumentNullException" />
        /// <remarks>The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.</remarks>
        /// <exception cref="ArgumentOutOfRangeException"><c>sinceId</c> is out of range.</exception>
        public Collection<Tweet> GetUsersTimeline(string screenName, ulong sinceId)
        {
            if (string.IsNullOrEmpty(screenName)) throw new ArgumentNullException("screenName");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("screen_name", screenName),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent statuses posted by the specified user.
        ///</summary>
        ///<param name="userId">The ID of the user for whom to return results for</param>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<returns>List of tweets</returns>
        ///<exception cref="ArgumentOutOfRangeException" />
        /// <remarks>The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.</remarks>
        public Collection<Tweet> GetUsersTimeline(ulong userId, ulong sinceId)
        {
            if (userId < 1) throw new ArgumentOutOfRangeException("userId");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("user_id", userId.ToString()),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent statuses posted by the specified user.
        ///</summary>
        ///<param name="screenName">The screen name of the user for whom to return results for</param>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<param name="count">Specifies the number of records to retrieve</param>
        ///<returns>List of tweets</returns>
        ///<exception cref="ArgumentOutOfRangeException" />
        ///<exception cref="ArgumentNullException" />
        /// <remarks>The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.</remarks>
        public Collection<Tweet> GetUsersTimeline(string screenName, ulong sinceId, uint count)
        {
            if (string.IsNullOrEmpty(screenName)) throw new ArgumentNullException("screenName");
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("screen_name", screenName),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent statuses posted by the specified user.
        ///</summary>
        ///<param name="userId">The ID of the user for whom to return results for</param>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<param name="count">Specifies the number of records to retrieve</param>
        ///<returns>List of tweets</returns>
        ///<exception cref="ArgumentOutOfRangeException" />
        /// <remarks>The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.</remarks>
        public Collection<Tweet> GetUsersTimeline(ulong userId, ulong sinceId, uint count)
        {
            if (userId < 1) throw new ArgumentOutOfRangeException("userId");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("user_id", userId.ToString()),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent statuses posted by the authenticating user.
        ///</summary>
        ///<param name="screenName">The screen name of the user for whom to return results for</param>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<param name="countPerPage">Specifies the number of records to retrieve</param>
        ///<param name="page"></param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of tweets</returns>
        ///<exception cref="ArgumentNullException"></exception>
        /// <remarks>The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.</remarks>
        public Collection<Tweet> GetUsersTimeline(string screenName, ulong sinceId, uint countPerPage, uint page)
        {
            if (string.IsNullOrEmpty(screenName)) throw new ArgumentNullException("screenName");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (countPerPage < 1 || countPerPage > 200) throw new ArgumentOutOfRangeException("countPerPage");
            if (page < 1) throw new ArgumentOutOfRangeException("page");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("screen_name", screenName),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent statuses posted by the authenticating user.
        ///</summary>
        ///<param name="userId">The ID of the user for whom to return results for</param>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<param name="countPerPage">Specifies the number of records to retrieve</param>
        ///<param name="page">Specifies the page of results to retrieve</param>
        ///<returns>List of tweets</returns>
        ///<exception cref="ArgumentOutOfRangeException" />
        /// <remarks>The timeline returned is the equivalent of the one seen when you view a user's profile on twitter.com.</remarks>
        public Collection<Tweet> GetUsersTimeline(ulong userId, ulong sinceId, uint countPerPage, uint page)
        {
            if (userId < 1) throw new ArgumentOutOfRangeException("userId");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (countPerPage < 1 || countPerPage > 200) throw new ArgumentOutOfRangeException("countPerPage");
            if (page < 1) throw new ArgumentOutOfRangeException("page");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/user_timeline.xml",
                                        true,
                                        new KeyValuePair<string, string>("user_id", userId.ToString()),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent mentions (status containing @username) for the authenticating user.
        ///</summary>
        ///<returns>List of mentions</returns>
        /// <remarks>The timeline returned is the equivalent of the one seen when you view your mentions on twitter.com.</remarks>
        public Collection<Tweet> GetMentions()
        {
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/mentions.xml",
                                        true);
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns <i>count</i> most recent mentions (status containing @username) for the authenticating user.
        /// </summary>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        /// <param name="count">Number of tweets to retrieve (must be less than or equal to 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of mentions</returns>
        /// <remarks>The timeline returned is the equivalent of the one seen when you view your mentions on twitter.com.</remarks>
        public Collection<Tweet> GetMentions(ulong sinceId, uint count)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/mentions.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent mentions (status containing @username) for the authenticating user.
        ///</summary>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of mention</returns>
        /// <remarks>The timeline returned is the equivalent of the one seen when you view your mentions on twitter.com.</remarks>
        public Collection<Tweet> GetMentions(ulong sinceId)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/mentions.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent mentions (status containing @username) for the authenticating user.
        ///</summary>
        ///<param name="count">Specifies the number of records to retrieve</param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of mentions</returns>
        /// <remarks>The timeline returned is the equivalent of the one seen when you view your mentions on twitter.com.</remarks>
        public Collection<Tweet> GetMentions(uint count)
        {
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/mentions.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent mentions (status containing @username) for the authenticating user.
        ///</summary>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<param name="countPerPage">Specifies the number of records to retrieve</param>
        ///<param name="page">Specifies the page of results to retrieve</param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of mentions</returns>
        /// <remarks>The timeline returned is the equivalent of the one seen when you view your mentions on twitter.com.</remarks>
        public Collection<Tweet> GetMentions(ulong sinceId, uint countPerPage, uint page)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (countPerPage < 1 || countPerPage > 200) throw new ArgumentOutOfRangeException("countPerPage");
            if (page < 1) throw new ArgumentOutOfRangeException("page");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/mentions.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the 20 most recent statuses, including retweets if they exist, from non-protected users.
        /// </summary>
        /// <returns>List of tweets</returns>
        /// <remarks>The public timeline is cached for 60 seconds. Requesting more frequently than that will not return any more data, and will count against your rate limit usage.</remarks>
        public Collection<Tweet> GetPublicTimeline()
        {
            var result = SendRequest(RequestMethod.Get, "https://api.twitter.com/1/statuses/public_timeline.xml",
                                        true);
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the <i>count</i> most recent retweets posted by the authenticating user.
        /// </summary>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        /// <param name="count">Number of tweets to retrieve (must be less than or equal to 200)</param>
        /// <exception cref="ArgumentOutOfRangeException" />
        /// <returns>List of tweets</returns>
        public Collection<Tweet> GetRetweetedByMe(ulong sinceId, uint count)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_by_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent retweets posted by the authenticating user.
        ///</summary>
        ///<returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedByMe()
        {
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_by_me.xml",
                                        true);
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent retweets posted by the authenticating user.
        ///</summary>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<returns>List of retweets</returns>
        /// <exception cref="ArgumentOutOfRangeException"><c>sinceId</c> is out of range.</exception>
        public Collection<Tweet> GetRetweetedByMe(ulong sinceId)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_by_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent retweets posted by the authenticating user.
        ///</summary>
        ///<param name="count">Specifies the number of records to retrieve</param>
        ///<returns></returns>
        /// <exception cref="ArgumentOutOfRangeException"><c>count</c> is out of range.</exception>
        public Collection<Tweet> GetRetweetedByMe(uint count)
        {
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_by_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent retweets posted by the authenticating user.
        ///</summary>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<param name="countPerPage">Specifies the number of records to retrieve</param>
        ///<param name="page">Specifies the page of results to retrieve</param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedByMe(ulong sinceId, uint countPerPage, uint page)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (countPerPage < 1 || countPerPage > 200) throw new ArgumentOutOfRangeException("countPerPage");
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_by_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the <i>count</i> most recent retweets posted by users the authenticating user follow.
        /// </summary>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        /// <param name="count">Number of tweets to retrieve (must be less than or equal to 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of tweets</returns>
        public Collection<Tweet> GetRetweetedToMe(ulong sinceId, uint count)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_to_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent retweets posted by users the authenticating user follow.
        ///</summary>
        ///<returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedToMe()
        {
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_to_me.xml",
                                        true);
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent retweets posted by users the authenticating user follow.
        ///</summary>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedToMe(ulong sinceId)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_to_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent retweets posted by users the authenticating user follow.
        ///</summary>
        ///<param name="count">Specifies the number of records to retrieve</param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedToMe(uint count)
        {
            if (count < 1) throw new ArgumentOutOfRangeException("count");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_to_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent retweets posted by users the authenticating user follow.
        ///</summary>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<param name="countPerPage">Specifies the number of records to retrieve</param>
        ///<param name="page">Specifies the page of results to retrieve</param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedToMe(ulong sinceId, uint countPerPage, uint page)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (countPerPage < 1 || countPerPage > 200) throw new ArgumentOutOfRangeException("countPerPage");
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_to_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        /// <summary>
        /// Returns the <i>count</i> most recent tweets of the authenticated user that have been retweeted by others.
        /// </summary>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        /// <param name="count">Number of tweets to retrieve (must be less than or equal to 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedOfMe(ulong sinceId, uint count)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_of_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent tweets of the authenticated user that have been retweeted by others.
        ///</summary>
        ///<returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedOfMe()
        {
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_of_me.xml",
                                        true);
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the 20 most recent tweets of the authenticated user that have been retweeted by others.
        ///</summary>
        ///<param name="sinceId"></param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedOfMe(ulong sinceId)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_of_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>count</i> most recent tweets of the authenticated user that have been retweeted by others.
        ///</summary>
        ///<param name="count">Specifies the number of records to retrieve</param>
        ///<exception cref="ArgumentOutOfRangeException"></exception>
        ///<returns>List of retweets</returns>
        public Collection<Tweet> GetRetweetedOfMe(uint count)
        {
            if (count < 1 || count > 200) throw new ArgumentOutOfRangeException("count");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_of_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()));
            return ParseTimeline(result);
        }

        ///<summary>
        /// Returns the <i>countPerPage</i> most recent tweets of the authenticated user that have been retweeted by others.
        ///</summary>
        ///<param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID</param>
        ///<param name="countPerPage">Specifies the number of records to retrieve</param>
        ///<param name="page">Specifies the page of results to retrieve</param>
        ///<returns>List of retweets</returns>
        /// <exception cref="ArgumentOutOfRangeException"><c>sinceId</c> is out of range.</exception>
        public Collection<Tweet> GetRetweetedOfMe(ulong sinceId, uint countPerPage, uint page)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");
            if (countPerPage < 1 || countPerPage > 200) throw new ArgumentOutOfRangeException("countPerPage");
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/statuses/retweeted_of_me.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()),
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()));
            return ParseTimeline(result);
        }

        #endregion

        /// <summary>
        /// Parses document containing statuses retrieved from Twitter
        /// </summary>
        /// <param name="xmlString">XML string defining the XML document</param>
        /// <returns>List of parsed tweets</returns>
        private static Collection<Tweet> ParseTimeline(string xmlString)
        {
            var doc = XDocument.Parse(xmlString);

            // ReSharper disable PossibleNullReferenceException
            var statuses = doc.Element("statuses").Elements("status");
            // ReSharper restore PossibleNullReferenceException

            var result = statuses.Select(ParseStatus).ToList();

            result.Sort((t1, t2) => t1.Time.CompareTo(t2.Time));
            return new Collection<Tweet>(result);
        }
    }
}
